package Group9.TodoManager.Data;

import java.util.ArrayList;
import java.util.List;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

/**
 * NodeItem is the class of an object that is added to the JTree.
 * @author volkan cambazoglu
 * @author rupesh
 */
public class NodeItem implements TreeModel {

    private String nodeLabel;
    private Object nodeValue;
    private NodeItem parentNode;
    private List<NodeItem> childNodes;
    private List<TreeModelListener> treeModelListners;
    private NodeItem rootNode;

    /**
     * Constructor. It creates an instance of the class by using the parameters
     * @param nodeLabel label of the node
     * @param nodeValue value of the node
     */
    public NodeItem(String nodeLabel, String nodeValue) {

        this.nodeLabel = nodeLabel;
        this.nodeValue = nodeValue;
        this.parentNode = null;
        this.rootNode = null;

        treeModelListners = new ArrayList<TreeModelListener>();
        childNodes = new ArrayList<NodeItem>();
    }

    /**
     * Getter method for child nodes
     * @return childNotes list of nodes that are child
     */
    public List<NodeItem> getChildNodes() {
        return childNodes;
    }

    /**
     * Add a new child node
     * @param child new child to be added
     */
    public void addChildNode(NodeItem child) {
        child.parentNode = this;
        child.rootNode = this.rootNode;
        childNodes.add(child);
    }

    /**
     * Add several child nodes
     * @param childNodes list of child nodes
     */
    public void addChildNodes(List<NodeItem> childNodes) {
        for (NodeItem cn : childNodes) {
            addChildNode(cn);
        }
    }

    /**
     * Setter method for child nodes
     * @param childNodesList list of child nodes
     */
    public void setChildNodes(List<NodeItem> childNodesList) {
        childNodes.clear();
        for(NodeItem item : childNodesList)
            this.addChildNode(item);
    }

    /**
     * Getter method for node label
     * @return nodeLabel label of the node
     */
    public String getNodeLabel() {
        return nodeLabel;
    }

    /**
     * Setter method for label of the node
     * @param nodeLabel label of the node
     */
    public void setNodeLabel(String nodeLabel) {
        this.nodeLabel = nodeLabel;
    }

    /**
     * Getter method for value of the node
     * @return nodeValue value of the node
     */
    public Object getNodeValue() {
        return nodeValue;
    }

    /**
     * Setter method for value of node
     * @param nodeValue value of node
     */
    public void setNodeValue(Object nodeValue) {
        this.nodeValue = nodeValue;
    }

    /**
     * Getter method for parent node
     * @return parentNode parent of the node
     */
    public NodeItem getParentNode() {
        return parentNode;
    }

    /**
     * Getter method for count of child
     * @return count number of child nodes
     */
    public int getChildCount() {
        return  childNodes == null ? -1 : childNodes.size();
    }

    /**
     * Getter method for child node
     * @param index index of the child node
     * @return node child node that is looked for
     */
    public NodeItem getChild(int index) {
        return childNodes == null || index > childNodes.size()
                ? null : childNodes.get(index);
    }

    /**
     * Getter method for root node
     */
    public Object getRoot() {
        return this.rootNode == null ? this : this.rootNode;
    }

    /**
     * Getter method for Child
     * @param parent parent of the node
     * @param index index of the node in the list of parent
     * @return node child node that is looked for
     */
    public Object getChild(Object parent, int index) {
        return ((NodeItem)parent).getChild(index);
    }

    /**
     * Getter method for count of child nodes
     * @param parent the node that has the child nodes
     * @return count number of child nodes
     */
    public int getChildCount(Object parent) {
        return ((NodeItem)parent).getChildCount();
    }

    /**
     * Checks if the node is a leaf node
     * @param node node that is queried
     * @return true if yes, false else
     */
    public boolean isLeaf(Object node) {
        return ((NodeItem)node).getChildCount() == 0;
    }

    /**
     * When the path of the tree is changed, gets the new value
     * @param path new path
     * @param newValue new value
     */
    public void valueForPathChanged(TreePath path, Object newValue) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * Getter method of index of child
     * @param parent parent node
     * @param child child node that is looked for
     * @return index index of the child
     */
    public int getIndexOfChild(Object parent, Object child) {
        return ((NodeItem)parent).getIndexOfChild((NodeItem)child);
    }

    /**
     * Getter method of index of child
     * @param child child node that is looked for
     * @return index index of the child
     */
    public int getIndexOfChild(NodeItem child) {
        int i = 0;
        for(NodeItem item : childNodes) {
            if(item == child)
                return i;
            i++;
        }
        return -1;
    }

    /**
     * Adds new tree model listener to the tree model
     * @param l TreeModelListener
     */
    public void addTreeModelListener(TreeModelListener l) {
        treeModelListners.add(l);
    }

    /**
     * Removes tree model listener from the tree model
     * @param l TreeModelListener
     */
    public void removeTreeModelListener(TreeModelListener l) {
        treeModelListners.remove(l);
    }

    /**
     * Creates corresponding string of the NodeItem object
     * In this case, returns nodeLabel
     */
    @Override
    public String toString() {
        return this.nodeLabel;
    }
}